package cn.springspace.kotlinapp

import org.bson.types.ObjectId
import org.springframework.boot.ApplicationRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.ApplicationEvent
import org.springframework.context.ApplicationListener
import org.springframework.context.event.ContextRefreshedEvent
import org.springframework.context.event.EventListener
import org.springframework.context.support.beans
import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.http.MediaType
import org.springframework.http.MediaType.TEXT_HTML
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.function.server.body
import org.springframework.web.reactive.function.server.router
import reactor.core.publisher.Flux
import java.time.Duration
import java.util.*
import java.util.stream.Stream

@SpringBootApplication
class KotlinAppApplication {
    @EventListener
    fun requestHandledEventListener(event: ApplicationEvent) {
        println("系统时间：${Calendar.getInstance()} 事件名称：${event.javaClass.simpleName}")
    }
}

interface BookRepository : ReactiveMongoRepository<Book, String>

@Document
data class Book(val id: ObjectId?, val name: String, val author: String, val publish: Date)

fun main(args: Array<String>) {
    runApplication<KotlinAppApplication>(*args) {
        addInitializers(
                beans {
                    bean("contextRefreshedEventListener") {
                        ApplicationListener<ContextRefreshedEvent> { event ->
                            println("容器刷新事件：$event")
                        }
                    }

                    bean("postHandler") {
                        val bookRestHandler = ref<RestBookHandler>()
                        router {
                            POST("/add", bookRestHandler::saveBook)
                        }
                    }

                    bean {
                        val bookRepository = ref<BookRepository>()
                        val interval = Flux.interval(Duration.ofMillis(100))
                        router {
                            (accept(TEXT_HTML) and "/book").nest {
                                GET("/list")
                                {
                                    ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM)
                                            .body(Flux.zip(interval, bookRepository.findAll()).map { entry -> entry.t2 })
                                }
                                GET("/get/{id}")
                                { request ->
                                    ServerResponse.ok().body(bookRepository.findById(request.pathVariable("id")))
                                }
                                GET("/get")
                                { request ->
                                    val id = request.queryParam("id")
                                    ServerResponse.ok().body(bookRepository.findById(id.get()))
                                }
                            }
                        }
                    }

                    bean {
                        val bookRepository = ref<BookRepository>()
                        ApplicationRunner {
                            bookRepository.deleteAll()
                                    .thenMany(Flux.fromStream(Stream.generate { ObjectId.get() }.limit(5)))
                                    .map { Book(it, "Spring创客空间（Spring Space）", "陈毕超", Date()) }
                                    .flatMap { bookRepository.save(it) }
                                    .thenMany(bookRepository.findAll())
                                    .subscribe { println(it) }
                        }
                    }
                }
        )
    }
}
